package com.quick.develop.business.handle;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.quick.develop.business.enums.BusinessTaskDefinition;
import com.quick.develop.business.execution.TaskExecution;
import com.quick.develop.business.execution.TaskExecutionDefinition;
import com.quick.develop.business.vo.BusinessProcessVO;
import com.quick.develop.flowable.domain.vo.process.BpmProcessReqVO;
import com.quick.develop.flowable.domain.vo.task.BpmTaskReqVO;
import com.quick.develop.flowable.enums.BpmExecuteCmd;
import com.quick.develop.framework.common.exception.ServerException;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

import static com.quick.develop.flowable.enums.BpmExecuteCmd.*;

@Slf4j
public abstract class AbstractTaskHandler implements TaskHandle {

    Map<String, List<TaskExecutionDefinition>> handlers = new HashMap<>(BpmExecuteCmd.values().length);

    static final BpmExecuteCmd[] COMPLETE_TASKS = new BpmExecuteCmd[]{
            AGREE, APPROVE, SUBMIT, RESOLVE, DISAGREE
    };

    @Override
    public void execute(BusinessProcessVO processVO) {
        BpmProcessReqVO process = processVO.getProcess();
        if (Objects.isNull(process)) {
            log.error("业务流程为空.");
            return;
        }
        BpmTaskReqVO task = processVO.getTask();
        if (Objects.isNull(task)) {
            log.error("业务任务为空.");
            return;
        }
        log.info("开始处理自定义任务: {}", task);
        execution(processVO);
        log.info("自定义任务处理完成: {}", task);
        String executeCmd = process.getExecuteCmd();
        BpmExecuteCmd bpmExecute = getBpmExecute(executeCmd);
        if (Objects.isNull(bpmExecute)) {
            throw new ServerException("不支持的流程执行命令: " + executeCmd);
        }
        if (isCompleteTask(bpmExecute)) {
            log.info("开始处理完成任务: {}", task.getTaskDefinitionName());
            complete(processVO);
            log.info("完成任务处理完成: {}", task.getTaskDefinitionName());
        }
        if (isRollbackTask(bpmExecute)) {
            log.info("开始处理退回任务: {}", task.getTaskDefinitionName());
            rollback(processVO);
            log.info("退回任务处理完成: {}", task.getTaskDefinitionName());
        }
        if (isStopProcess(bpmExecute)) {
            log.info("开始处理停止流程任务: {}", task.getTaskDefinitionName());
            stop(processVO);
            log.info("停止流程任务处理完成: {}", task.getTaskDefinitionName());
        }
    }

    public void execute(String type, BusinessTaskDefinition[] definitions, BusinessProcessVO businessProcessVO) {
        StringJoiner joiner = new StringJoiner(StrUtil.DASHED);
        joiner.add(type);
        for (BusinessTaskDefinition definition : definitions) {
            joiner.add(definition.getBeanName());
        }
        String key = joiner.toString();
        List<TaskExecutionDefinition> executions = handlers.get(key);
        if (Objects.isNull(executions)) {
            executions = new ArrayList<>();
            for (BusinessTaskDefinition definition : definitions) {
                Object bean = SpringUtil.getBean(definition.getBeanName());
                if (Objects.isNull(bean)) {
                    log.error("任务处理器: {} 未找到", definition.getBeanName());
                    throw new RuntimeException("任务处理器未定义：" + definition.getBeanName());
                }
                if (!(bean instanceof TaskExecution)) {
                    log.error("任务处理器: {} 不是TaskExecution类型", definition.getBeanName());
                    throw new RuntimeException("任务处理器类型错误：" + definition.getBeanName());
                }
                TaskExecutionDefinition executionDefinition = new TaskExecutionDefinition();
                executionDefinition.setExecution((TaskExecution) bean);
                executionDefinition.setDefinition(definition);
                executions.add(executionDefinition);
            }
            handlers.put(key, executions);
        }
        for (TaskExecutionDefinition executionDefinition : executions) {
            BusinessTaskDefinition definition = executionDefinition.getDefinition();
            log.info("开始执行任务: {}", definition.getDesc());
            try {
                TaskExecution execution = executionDefinition.getExecution();
                execution.execute(businessProcessVO);
            } catch (Exception e) {
                log.error("执行任务: {} 失败,异常信息：{}", definition.getDesc(), e.getMessage());
                throw new RuntimeException(e.getMessage());
            }
            log.info("执行任务完成：{}", definition.getDesc());
        }
    }

    /**
     * @param processVO 业务流程数据
     */
    abstract void execution(BusinessProcessVO processVO);

    /**
     * @param processVO 业务流程数据
     */
    abstract void complete(BusinessProcessVO processVO);

    /**
     * @param processVO 业务流程数据
     */
    abstract void rollback(BusinessProcessVO processVO);

    /**
     * @param processVO 业务流程数据
     */
    abstract void stop(BusinessProcessVO processVO);

    protected boolean isCompleteTask(BpmExecuteCmd cmd) {
        return Arrays.stream(COMPLETE_TASKS).anyMatch(t -> Objects.equals(t.cmd, cmd.cmd));
    }

    protected boolean isRollbackTask(BpmExecuteCmd cmd) {
        return Objects.equals(cmd.getCmd(), BpmExecuteCmd.BACK.cmd);
    }

    protected boolean isStopProcess(BpmExecuteCmd cmd) {
        return Objects.equals(cmd.getCmd(), BpmExecuteCmd.STOP.cmd);
    }

}
